
package com.smartfit;

import java.text.DecimalFormat;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;

public abstract class AccelerometerSensorActivity extends Activity implements SensorEventListener
{
	// 실수의 출력 자리수를 지정하는 포맷 객체
    DecimalFormat m_DecimalFormat;

    // 센서 매니저
	private SensorManager sensorMgr;
	// 가속도 센서
	private Sensor accelerometerSensor;
	private int acceleraterType;
	
	// ���ӵ� ���� ����
	
	long lastTimeOfAccel = 0;
	
	AccelSensorData sensorData = new AccelSensorData();

	float speed = 0.0f;
	Axis3f m_Gravity = new Axis3f();

	// 센서 데이터 추출 진행여부
	protected boolean m_bIsConnectSensor = false;
	// 데이터에 중력값을 포함할 지 유무
	protected boolean m_bIsContainedGravity = true;
	// 노이즈
	protected double m_fNoise = 0.0;
	// 샘플데이터 시간간격
	protected int m_iTimeInterval = 100;
	
	// 센서정보 알림 콜백
	public abstract void NotifySensorEvent( AccelSensorData sensorData );
	public abstract void NotifySensorOrientationEvent( double x , double y , double z );
	public abstract void NotifySensorDistanceEvent( double x , double y , double z );

	@Override
	protected void onCreate( Bundle savedInstanceState )
	{
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);

		// text view
		m_DecimalFormat = new DecimalFormat();
		m_DecimalFormat.applyLocalizedPattern( "0.##" );
	}

	@Override
	protected void onResume()
	{
		// TODO Auto-generated method stub
		super.onResume();
	}

	@Override
	protected void onPause()
	{
		// TODO Auto-generated method stub
		super.onPause();
		
		DisconnectSensor();
	}

	protected void InitializeSensor()
	{
		// ������ ����Ǿ����� ����
		m_bIsConnectSensor = false;

		// ���ӵ� ���� ���� ������ ��
		sensorMgr = ( SensorManager )getSystemService( SENSOR_SERVICE );
		
		SmartFitApp app = ( ( SmartFitApp )( getApplicationContext() ) );
		acceleraterType = Sensor.TYPE_ACCELEROMETER;
		/*
		if ( app.m_ExamplarDB.IsContainedGravity() )
		{
			acceleraterType = Sensor.TYPE_ACCELEROMETER;
		}
		else
		{
			acceleraterType = Sensor.TYPE_LINEAR_ACCELERATION;
		}
		*/
		
		accelerometerSensor = sensorMgr.getDefaultSensor( acceleraterType );
	}

	protected boolean ConnectSensor()
	{
		if ( m_bIsConnectSensor )
		{
			return false;
		}
	
    	if ( accelerometerSensor != null )
    	{
    		//
    		SmartFitApp app = ( ( SmartFitApp )getApplicationContext() );
    		
    		m_bIsContainedGravity = app.m_ExamplarDB.IsContainedGravity();
    		m_iTimeInterval = app.m_ExamplarDB.GetTimeInterval();
    		// 노이즈
    		m_fNoise = app.m_ExamplarDB.GetNoiseValue();

    		// 센서 정보 읽기 시작 저장
    		m_bIsConnectSensor = true;
    		// 센서 정보 초기화
    		sensorData.Clear();
    		// 중력정보
    		m_Gravity.Clear();
    		
    		// 가속도 센서
    		sensorMgr.registerListener( this , accelerometerSensor, SensorManager.SENSOR_DELAY_GAME );
    	}

    	return m_bIsConnectSensor;
	}
	
	protected void DisconnectSensor()
	{
		// 센서정보 읽기 종료
		m_bIsConnectSensor = false;

    	if ( accelerometerSensor != null )
    	{
    		sensorMgr.unregisterListener( this );
    	}
	}
/*	
	@Override
	public void onSensorChanged( SensorEvent event )
	{
		if ( m_bIsConnectSensor == false )
		{
			return;
		}
		
		if ( event.sensor.getType() == acceleraterType )
        {
			long currentTime = System.currentTimeMillis();

			double x = ( double )( event.values[0] );
            double y = ( double )( event.values[1] );
            double z = ( double )( event.values[2] );
			
            if ( sensorData.initialized == false )
			{
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].x = x;
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].y = y;
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].z = z;
				
	            sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].x = x;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].y = y;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].z = z;
				
				lastTimeOfAccel = currentTime;
				sensorData.initialized = true;
			}
			else
			{
				long elapsedTime = ( currentTime - lastTimeOfAccel );

				if ( elapsedTime < m_iTimeInterval )
				{
					return;
				}
			
				double fTime = ( double )( ( double )elapsedTime / 1000 );
				
				lastTimeOfAccel = currentTime;
				
	            SmartFitApp app = ( ( SmartFitApp )( getApplicationContext() ) );
	            
	            // 노이즈 제거
	            
	            if ( Math.abs( x ) < m_fNoise )
	            {
	            	x = 0.0;
	            }
	            
	            if ( Math.abs( y ) < m_fNoise )
	            {
	            	y = 0.0;
	            }

	            if ( Math.abs( z ) < m_fNoise )
	            {
	            	z = 0.0;
	            }

	            // 칼만필터
	            
	            if ( app.m_ExamplarDB.IsAppliedKalmanFilter() )
				{
					x = sensorData.filterX.Update( x );
					y = sensorData.filterY.Update( y );
					z = sensorData.filterZ.Update( z );
				}
	            
	            //
	            // 센서데이터
	            //
	            
	            // 가속도
	            
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].x = x;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].y = y;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].z = z;

				// 각도
	            
	            sensorData.fPitch = Math.atan( x / Math.sqrt( ( y * y ) + ( z * z ) ) );
	            sensorData.fRoll = Math.atan( y / Math.sqrt( ( x * x ) + ( z * z ) ) );
	            sensorData.fTheta = Math.atan( Math.sqrt( ( x * x ) + ( y * y ) ) / z );
			}
        }
	}
*/	
	@Override
	public void onSensorChanged( SensorEvent event )
	{
		// TODO Auto-generated method stub
		
		if ( m_bIsConnectSensor == false )
		{
			return;
		}
		
		long currentTime = System.currentTimeMillis();

		if ( event.sensor.getType() == acceleraterType )
        {
    		double x = ( double )( event.values[0] );
            double y = ( double )( event.values[1] );
            double z = ( double )( event.values[2] );
            
            final float alpha = 0.8f;
            
            m_Gravity.x = alpha * m_Gravity.x + ( 1 - alpha ) * x;
            m_Gravity.y = alpha * m_Gravity.y + ( 1 - alpha ) * y;
            m_Gravity.z = alpha * m_Gravity.z + ( 1 - alpha ) * z;
            
            SmartFitApp app = ( ( SmartFitApp )( getApplicationContext() ) );
            
    		String strAccelWithGravity = m_DecimalFormat.format( x ) + " , " + m_DecimalFormat.format( y ) + " , " + m_DecimalFormat.format( z );
    		Log.d( "1 : " , strAccelWithGravity );

            if ( app.m_ExamplarDB.IsContainedGravity() == false )
            {
	            x = x - m_Gravity.x;
	            y = y - m_Gravity.y;
	            z = z - m_Gravity.z;

	    		String strAccelWithoutGravity = m_DecimalFormat.format( x ) + " , " + m_DecimalFormat.format( y ) + " , " + m_DecimalFormat.format( z );
	    		Log.d( "2 : " , strAccelWithoutGravity );
            }
            
			if ( sensorData.initialized == false )
			{
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].x = x;
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].y = y;
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].z = z;
				
	            sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].x = x;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].y = y;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].z = z;

				sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].x = 0;
				sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].y = 0;
				sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].z = 0;
				
				sensorData.position[AccelSensorData.SENSOR_PREV_DATA].x = 0;
				sensorData.position[AccelSensorData.SENSOR_PREV_DATA].y = 0;
				sensorData.position[AccelSensorData.SENSOR_PREV_DATA].z = 0;
				
				lastTimeOfAccel = currentTime;
				sensorData.initialized = true;
			}
			else
			{
				long elapsedTime = ( currentTime - lastTimeOfAccel );
				
				if ( elapsedTime < m_iTimeInterval )
				{
					return;
				}
			
				double fTime = ( double )( ( double )elapsedTime / 1000 );
				
				lastTimeOfAccel = currentTime;
	            
	            // 노이즈 제거
	            
	            if ( Math.abs( x ) < m_fNoise )
	            {
	            	x = 0.0;
	            }
	            
	            if ( Math.abs( y ) < m_fNoise )
	            {
	            	y = 0.0;
	            }

	            if ( Math.abs( z ) < m_fNoise )
	            {
	            	z = 0.0;
	            }
	            
	            // 가속도 ^ 2
	            
	            if ( app.m_ExamplarDB.IsAppliedSquare() )
	            {
	            	if ( x > 0.0 )
	            	{
	            		x = x * x;
	            	}
	            	else
	            	{
	            		x = x * x;
	            		x *= -1.0;
	            	}
	            	
	            	if ( y > 0.0 )
	            	{
	            		y = y * y;
	            	}
	            	else
	            	{
	            		y = y * y;
	            		y *= -1;
	            	}
	            	
	            	if ( z > 0.0 )
	            	{
	            		z = z * z;
	            	}
	            	else
	            	{
	            		z = z * z;
	            		z *= -1;
	            	}
	            	
	            }

	            // 칼만필터
	            
	            if ( app.m_ExamplarDB.IsAppliedKalmanFilter() )
				{
					x = sensorData.filterX.Update( x );
					y = sensorData.filterY.Update( y );
					z = sensorData.filterZ.Update( z );
				}
	            
	            //
	            // 센서데이터
	            //
	            
	            // 가속도
	            
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].x = sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].x;
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].y = sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].y;
				sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].z = sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].z;

				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].x = x;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].y = y;
				sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].z = z;

				// 각도
	            
	            sensorData.fPitch = Math.atan( x / Math.sqrt( ( y * y ) + ( z * z ) ) );
	            sensorData.fRoll = Math.atan( y / Math.sqrt( ( x * x ) + ( z * z ) ) );
	            sensorData.fTheta = Math.atan( Math.sqrt( ( x * x ) + ( y * y ) ) / z );

	    		// 속도
	            
				x = CalculateVelocity(
						sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].x ,
						sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].x ,
						sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].x ,
						fTime );
				
				y = CalculateVelocity(
						sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].y ,
						sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].y ,
						sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].y ,
						fTime );
	
				z = CalculateVelocity(
						sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].z ,
						sensorData.acceleration[AccelSensorData.SENSOR_PREV_DATA].z ,
						sensorData.acceleration[AccelSensorData.SENSOR_CURR_DATA].z ,
						fTime );

				sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].x = x;
				sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].y = y;
				sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].z = z;

				// 위치
	            
				x = CalculateDistance(
						sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].x ,
						sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].x ,
						fTime );
				
				y = CalculateDistance(
						sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].y ,
						sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].y ,
						fTime );
	
				z = CalculateDistance(
						sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].z ,
						sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].z ,
						fTime );

				sensorData.position[AccelSensorData.SENSOR_CURR_DATA].x = x;
				sensorData.position[AccelSensorData.SENSOR_CURR_DATA].y = y;
				sensorData.position[AccelSensorData.SENSOR_CURR_DATA].z = z;

				// 센서데이터 처리
				NotifySensorEvent( sensorData );
				
				NotifySensorDistanceEvent( 
						Math.abs( sensorData.position[AccelSensorData.SENSOR_CURR_DATA].x ) , 
						Math.abs( sensorData.position[AccelSensorData.SENSOR_CURR_DATA].y ) ,
						Math.abs( sensorData.position[AccelSensorData.SENSOR_CURR_DATA].z ) );

	
				sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].x = sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].x;
				sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].y = sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].y;
				sensorData.velocity[AccelSensorData.SENSOR_PREV_DATA].z = sensorData.velocity[AccelSensorData.SENSOR_CURR_DATA].z;
				
				sensorData.position[AccelSensorData.SENSOR_PREV_DATA].x = sensorData.position[AccelSensorData.SENSOR_CURR_DATA].x;
				sensorData.position[AccelSensorData.SENSOR_PREV_DATA].y = sensorData.position[AccelSensorData.SENSOR_CURR_DATA].y;
				sensorData.position[AccelSensorData.SENSOR_PREV_DATA].z = sensorData.position[AccelSensorData.SENSOR_CURR_DATA].z;
			}
        }
	}

	@Override
	public void onAccuracyChanged( Sensor sensor , int accuracy )
	{
		// TODO Auto-generated method stub
		
	}
	
	double CalculateVelocity( double fBase , double fDiff0 , double fDiff1 , double fTime )
	{
//		String strCalculateIntegration = "base = " + m_DecimalFormat.format( fBase ) + " , fDiff0 = " + m_DecimalFormat.format( fDiff0 ) + " , fDiff1 = " + m_DecimalFormat.format( fDiff1 ) + " , fTime = " + m_DecimalFormat.format( fTime );
//		Log.d( "CalculateIntegration" , strCalculateIntegration );
		

//		return ( double )( fBase + ( fDiff0 + ( ( fDiff1 - fDiff0 ) / 2 ) ) * fTime );
		return ( double )( ( fDiff0 + ( ( fDiff1 - fDiff0 ) / 2 ) ) * fTime );
	}

	double CalculateDistance( double fDiff0 , double fDiff1 , double fTime )
	{
//		String strCalculateIntegration = " , fDiff0 = " + m_DecimalFormat.format( fDiff0 ) + " , fDiff1 = " + m_DecimalFormat.format( fDiff1 ) + " , fTime = " + m_DecimalFormat.format( fTime );
//		String strCalculateIntegration = " , fDiff0 = " + Double.toString( fDiff0 ) + " , fDiff1 = " + Double.toString( fDiff1 ) + " , fTime = " + Double.toString( fTime );
//		Log.d( "CalculateIntegration" , strCalculateIntegration );

//		return Math.abs( ( double )( ( fDiff0 + ( ( fDiff1 - fDiff0 ) / 2 ) ) * fTime ) );
		return ( double )( ( fDiff0 + ( ( fDiff1 - fDiff0 ) / 2 ) ) * fTime );
	}

	/*
	double CalculateDistance( double v0 , double v1 , double a )
	{
		double d = 2 * a;
		
		if ( d == 0 )
		{
			d = 1;
		}
		
		return ( ( v1 * v1 - v0 * v0 ) / d );
	}
	*/
}